package com.dkd.sbtz.service.impl;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import com.dkd.common.utils.DateUtils;
import com.dkd.common.utils.SecurityUtils;
import com.dkd.common.utils.StringUtils;
import com.dkd.sbtz.domain.AssetMtplanSpare;
import com.dkd.sbtz.domain.Spare;
import com.dkd.sbtz.domain.mtplan.MtplanSpareHistoryVO;
import com.dkd.sbtz.domain.plando.*;
import com.dkd.sbtz.domain.vo.MtPlanCreateReq;
import com.dkd.sbtz.domain.vo.PlanQuery;
import com.dkd.sbtz.domain.vo.spare.SpecialItemDTO;
import com.dkd.sbtz.mapper.SpareMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dkd.sbtz.mapper.AssetMtplanMapper;
import com.dkd.sbtz.domain.AssetMtplan;
import com.dkd.sbtz.service.IAssetMtplanService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备计划维护Service业务层处理
 * 
 * @author xzj
 * @date 2025-09-19
 */
@Service
public class AssetMtplanServiceImpl implements IAssetMtplanService 
{
    @Autowired
    private AssetMtplanMapper assetMtplanMapper;

    @Autowired
    private SpareMapper spareMapper;

    private static final int SPARE_TYPE_SPECIAL = 1;

//    @Override
//    public List<AssetMtplan> selectAssetMtplanList(AssetMtplan query) {
//        return assetMtplanMapper.selectAssetMtplanList(query);
//    }

//    @Override
//    public List<AssetMtplan> selectAssetMtplanList(AssetMtplan query) {
//        // ① 受 startPage() 影响，先查一页主表
//        List<AssetMtplan> list = assetMtplanMapper.selectAssetMtplanList(query);
//        if (list == null || list.isEmpty()) return list;
//
//        // ② 收集 planIds，批量查子表
//        List<Long> planIds = list.stream().map(AssetMtplan::getId).toList();
//        List<AssetMtplanSpare> all = assetMtplanMapper.selectSpareInfoByPlanIds(planIds);
//
//        // ③ 分组回填
//        Map<Long, List<AssetMtplanSpare>> map =
//                all.stream().collect(java.util.stream.Collectors.groupingBy(AssetMtplanSpare::getPlanId));
//        for (AssetMtplan p : list) {
//            p.setSpares(map.getOrDefault(p.getId(), java.util.Collections.emptyList()));
//        }
//        return list;
//    }
    @Override
    public List<AssetMtplan> selectAssetMtplanList(AssetMtplan query) {
    // ① 受 startPage() 影响，只查一页主表
    List<AssetMtplan> list = assetMtplanMapper.selectAssetMtplanList(query);
    if (list == null || list.isEmpty()) return list;

    // ② 批量查关系
    List<Long> planIds = list.stream().map(AssetMtplan::getId).toList();
    List<AssetMtplanSpare> rels = assetMtplanMapper.selectSpareInfoByPlanIds(planIds);

    // ③ 批量查 spare 明细并建索引（★ 复用你已有的方法）
    java.util.Set<Long> spareIds = rels.stream()
            .map(AssetMtplanSpare::getSpareId)
            .filter(java.util.Objects::nonNull)
            .collect(java.util.stream.Collectors.toSet());

    java.util.Map<Long, Spare> spareMap =
            spareIds.isEmpty() ? java.util.Collections.emptyMap()
                    : spareMapper.selectByIds(new java.util.ArrayList<>(spareIds)).stream()
                    .collect(java.util.stream.Collectors.toMap(Spare::getId, java.util.function.Function.identity()));

    // ④ 把 spare 明细“并回”关系记录（填充到非表字段）
    for (AssetMtplanSpare m : rels) {
        Spare s = spareMap.get(m.getSpareId());
        if (s != null) {
            m.setSpare(s);                             // 整个对象
            m.setSpareName(s.getName());               // 直取展示字段（可选）
            m.setSpareCode(s.getCode());
            m.setUnit(s.getUnit());
            m.setSpareType(s.getIsSpecial());
            m.setStockTotal(s.getStockTotal());
            m.setStockAvailable(s.getStockAvailable());
            m.setSpareRemark(s.getRemark());
            m.setSpareStatus(s.getStatus());
            // 你表里有 plan_date / order_date
            m.setSparePlanDate(s.getPlanDate());
            m.setSpareOrderDate(s.getOrderDate());
        }
    }

    // ⑤ 分组回填到各计划
    java.util.Map<Long, List<AssetMtplanSpare>> byPlan =
            rels.stream().collect(java.util.stream.Collectors.groupingBy(AssetMtplanSpare::getPlanId));
    for (AssetMtplan p : list) {
        p.setSpares(byPlan.getOrDefault(p.getId(), java.util.Collections.emptyList()));
    }
    return list;
}




    @Override
    public AssetMtplan selectAssetMtplanDetail(Long planId) {
        AssetMtplan vo = assetMtplanMapper.selectAssetMtplanById(planId);
        if (vo == null) return null;
        vo.setSpares(assetMtplanMapper.selectByPlanId(planId));
        return vo;
    }

    @Override
    @Transactional
    public int insertAssetMtplan(AssetMtplan po) {
        String user = SecurityUtils.getUsername();
        if (StringUtils.isEmpty(po.getStatus())) po.setStatus("OPEN");
        if (po.getDeleted() == null) po.setDeleted(0);
        po.setCreateBy(user);
        po.setUpdateBy(user);

        int n = assetMtplanMapper.insertAssetMtplan(po);

        // 子表
        if (po.getNeedSpare() != null && po.getNeedSpare() == 1
                && po.getSpares() != null && !po.getSpares().isEmpty()) {

            List<AssetMtplanSpare> list = new ArrayList<>(po.getSpares().size());
            for (AssetMtplanSpare s : po.getSpares()) {
                if (s.getSpareId() == null) continue;
                AssetMtplanSpare m = new AssetMtplanSpare();
                m.setPlanId(po.getId());
                m.setSpareId(s.getSpareId());
                m.setQty(s.getQty() == null || s.getQty() < 1 ? 1 : s.getQty());
                m.setRemark(s.getRemark());
                m.setCreateBy(user);
                m.setAssetId(po.getAssetId());
                list.add(m);
            }
            if (!list.isEmpty()) assetMtplanMapper.batchInsert(list);
        }
        return n;
    }

    @Override
    @Transactional
    public int updateAssetMtplan(AssetMtplan po) {
        po.setUpdateBy(SecurityUtils.getUsername());
        // 主表字段更新（是否同步子表由前端决定，推荐调用 replacePlanSpares）
        return assetMtplanMapper.updateAssetMtplan(po);
    }


    @Override
    @Transactional
    public int deleteAssetMtplanByIds(Long[] ids) {
        return assetMtplanMapper.deleteAssetMtplanByIds(ids);
    }

    @Override
    public List<AssetMtplanSpare> selectPlanSpares(Long planId) {
        return assetMtplanMapper.selectByPlanId(planId);
    }

    @Override
    @Transactional
    public int updatePlanFields(AssetMtplan po) {
        // 可选：对 status 做白名单校验（你的库是 ENUM 或 VARCHAR）
        if (po.getStatus() != null) {
            String s = po.getStatus();
            if (!"OPEN".equals(s) && !"GENERATED".equals(s) && !"CANCELLED".equals(s) && !"DONE".equals(s)) {
                po.setStatus("OPEN");
            }
        }

        int n = assetMtplanMapper.updatePlanFields(po);

        // 可选：若 needSpare 从 1 改为 0，可以同步清空子表（按需开启）
//         if (po.getNeedSpare() != null && po.getNeedSpare() == 0) {
//             assetMtplanMapper.deleteByPlanId(po.getId());
//         }

        return n;
    }


    @Override
    public List<MtplanSpareHistoryVO> selectHistory(Long assetId, Long planId, String keyword, String beginTime, String endTime) {
        return assetMtplanMapper.selectHistoryByAssetId(assetId, planId, keyword, beginTime, endTime);
    }




    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPlan(AssetMtplan dto) {
        // 1) 保存计划
        dto.setCreateBy(SecurityUtils.getUsername());
        assetMtplanMapper.insertAssetMtplan(dto);         // useGeneratedKeys -> dto.id
        Long planId = dto.getId();

        handleSpecialItems(dto, planId);
        // 2) 处理备件
//        if (Objects.equals(dto.getSpareType(), 1)) {
//            handleSpecialItems(dto, planId);
//        } else {
//            handleNormalSpares(dto, planId);
//        }
        return planId;
    }

    /** 普通模式（略：按你的旧逻辑） */
    private void handleNormalSpares(AssetMtplan dto, Long planId) {
        if (dto.getSpares() == null) return;
        for (AssetMtplanSpare r : dto.getSpares()) {
            r.setPlanId(planId);
            r.setAssetId(dto.getAssetId());
            r.setQty(Math.max(1, Optional.ofNullable(r.getQty()).orElse(1)));
            r.setCreateBy(dto.getCreateBy());
            r.setUpdateBy(dto.getCreateBy());
            assetMtplanMapper.insertOrUpdate(r);
        }
    }

    private void handleSpecialItems(AssetMtplan dto, Long planId) {
        if (dto.getSpecialItems() == null || dto.getSpecialItems().isEmpty()) return;

        final String user = SecurityUtils.getUsername();
        final Date planDate = dto.getPlanDate();

        for (SpecialItemDTO it : dto.getSpecialItems()) {
            if (it == null) continue;
            Integer orderDays = Optional.ofNullable(it.getOrderDate()).orElse(0);
            Integer qty = Math.max(1, Optional.ofNullable(it.getQty()).orElse(1));

            // d) 写入关系表 asset_mtplan_spare
            AssetMtplanSpare rel = new AssetMtplanSpare();
            rel.setAssetId(dto.getAssetId());
            rel.setPlanId(planId);

            rel.setSpareId(it.getSpareId());
            rel.setPlanDate(planDate);
            rel.setOrderDate(orderDays);
            rel.setQty(qty);
            rel.setCreateBy(user);
            rel.setUpdateBy(user);
            assetMtplanMapper.insertOrUpdate(rel);
        }
    }


    /** 特殊模式：插入/更新 asset_spare，并写入关系表 */
//    private void handleSpecialItems(AssetMtplan dto, Long planId) {
//        if (dto.getSpecialItems() == null || dto.getSpecialItems().isEmpty()) return;
//
//        final String user = SecurityUtils.getUsername();
//        final Date planDate = dto.getPlanDate();
//
//        for (SpecialItemDTO it : dto.getSpecialItems()) {
//            if (it == null) continue;
//            String code = safeUpper(it.getCode());
//            String name = StringUtils.trimToEmpty(it.getName());
//            if (StringUtils.isBlank(code) || StringUtils.isBlank(name)) continue;
//
//            Integer orderDays = Optional.ofNullable(it.getOrderDate()).orElse(0);
//            Integer qty = Math.max(1, Optional.ofNullable(it.getQty()).orElse(1));
//
//            // a) 先按 code 查
//            Long spareId = spareMapper.selectIdByCode(code);
//
//            if (spareId == null) {
//                // b) 不存在 -> 新增 asset_spare
//                Spare s = new  Spare();
//                s.setCode(code);
//                s.setName(name);
//                s.setType(1);                   // 特殊
//                s.setStatus(0);
//                s.setUnit("个");
//                s.setStockTotal(0L);
//                s.setStockAvailable(0L);
//                s.setPlanDate(planDate);        // 计划日期
//                s.setOrderDate(orderDays);      // 采购周期(天)
//                s.setCreateBy(user);
//                s.setUpdateBy(user);
//                spareMapper.insertSpare(s);     // useGeneratedKeys -> s.id
//                spareId = s.getId();
//            } else {
//                // c) 已存在 -> 更新关键字段（名称/计划日期/采购周期）
//                spareMapper.updateSpecialFieldsByCode(code,  name, planDate, orderDays, user,it.getType());
//            }
//
//            // d) 写入关系表 asset_mtplan_spare
//            AssetMtplanSpare rel = new AssetMtplanSpare();
//            rel.setAssetId(dto.getAssetId());
//            rel.setPlanId(planId);
//            rel.setSpareId(spareId);
//            rel.setQty(qty);
//            rel.setCreateBy(user);
//            rel.setUpdateBy(user);
//            assetMtplanMapper.insertOrUpdate(rel);
//        }
//    }

    private static String safeUpper(String s) {
        if (s == null) return "";
        return s.trim().toUpperCase().replaceAll("[^A-Z0-9\\-_]", "");
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePlanCascade(Long[] ids) {
        List<Long> planIds = Arrays.asList(ids);

        // 1) 取这些计划涉及到的所有备件
        List<Long> allSpareIds = assetMtplanMapper.selectSpareIdsByPlanIds(planIds);
        List<Long> specialIds = allSpareIds.isEmpty()
                ? Collections.emptyList()
                : spareMapper.selectSpecialIdsByIds(allSpareIds); // 只保留 type=1

        // 2) 先删关系（避免外键/唯一冲突，也便于后面判断是否还有引用）
        assetMtplanMapper.deleteByPlanIds(planIds);

        // 3) 删除计划
        int n = assetMtplanMapper.deleteAssetMtplanByIds(ids);

        // 4) 清理“孤儿”的特殊备件（type=1 且不再被任何计划引用）
        if (!specialIds.isEmpty()) {
            List<Long> stillInUse = assetMtplanMapper.selectInUseSpareIds(specialIds); // 仍被其它计划用
            Set<Long> keep = new HashSet<>(stillInUse);
            List<Long> deletable = specialIds.stream()
                    .filter(id -> !keep.contains(id))
                    .collect(Collectors.toList());
            if (!deletable.isEmpty()) {
                spareMapper.deleteSpareByIds(deletable);
            }
        }
        return n;
    }


    @Override
    @Transactional
    public void replacePlanSpares(Long planId, List<AssetMtplanSpare> spares) {

        // 1) 记录本计划中“原来”关联的特殊备件ID集合
        List<AssetMtplanSpare> before = assetMtplanMapper.selectByPlanId(planId);
        Set<Long> oldSpecialIds = before == null ? Collections.emptySet()
                : before.stream()
                .filter(x -> x.getSpareType() != null && x.getSpareType() == SPARE_TYPE_SPECIAL)
                .map(AssetMtplanSpare::getSpareId)
                .collect(Collectors.toSet());

        // 2) 先删本计划所有关系
        assetMtplanMapper.deleteByPlanId(planId);
        cleanupOrphanSpecials(oldSpecialIds, Collections.emptySet());

        if (spares == null || spares.isEmpty()) return;
        String user = SecurityUtils.getUsername();

        List<AssetMtplanSpare> list = new ArrayList<>(spares.size());
        for (AssetMtplanSpare s : spares) {
            if (s.getSpareId() == null) continue;
            AssetMtplanSpare m = new AssetMtplanSpare();
            m.setPlanId(planId);
            m.setSpareId(s.getSpareId());
            m.setAssetId(s.getAssetId());
            m.setQty(s.getQty() == null || s.getQty() < 1 ? 1 : s.getQty());
            m.setRemark(s.getRemark());
            m.setCreateBy(user);
            list.add(m);
        }
        if (!list.isEmpty()) assetMtplanMapper.batchInsert(list);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replacePlanSpecialSpares(Long planId, List<SpecialItemDTO> items) {

        final String user = SecurityUtils.getUsername();
        if (items == null) items = Collections.emptyList();
        // 2) 先删本计划所有关系
        assetMtplanMapper.deleteByPlanId(planId);

        // 4) 重建关系（存在则更新，不存在则插入），收集本次保留的特殊备件ID
        List<AssetMtplanSpare> rels = new ArrayList<>(items.size());
        for (SpecialItemDTO it : items) {
            if (it == null) continue;
            // 4.2 建立 plan–spare 关系
            AssetMtplanSpare r = new AssetMtplanSpare();
            r.setPlanId(planId);
            r.setSpareId(it.getSpareId());
            r.setAssetId(it.getAssetId());
            r.setQty(it.getQty() == null || it.getQty() < 1 ? 1 : it.getQty());
            r.setOrderDate(it.getOrderDate());
            r.setPlanDate(it.getPlanDate());
            r.setRemark("");
            r.setCreateBy(user);
            rels.add(r);
        }

        if (!rels.isEmpty()) {
            assetMtplanMapper.batchInsert(rels);
        }
    }




//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void replacePlanSpecialSpares(Long planId, List<SpecialItemDTO> items) {
//
//        final String user = SecurityUtils.getUsername();
//        if (items == null) items = Collections.emptyList();
//
//        // 1) 记录本计划中“原来”关联的特殊备件ID集合
//        List<AssetMtplanSpare> before = assetMtplanMapper.selectByPlanId(planId);
//        Set<Long> oldSpecialIds = before == null ? Collections.emptySet()
//                : before.stream()
//                .filter(x -> x.getSpareType() != null && x.getSpareType() == SPARE_TYPE_SPECIAL)
//                .map(AssetMtplanSpare::getSpareId)
//                .collect(Collectors.toSet());
//
//        // 2) 先删本计划所有关系
//        assetMtplanMapper.deleteByPlanId(planId);
//
//        // 3) 空清单：清理孤儿后直接返回
//        if (items.isEmpty()) {
//            cleanupOrphanSpecials(oldSpecialIds, Collections.emptySet());
//            return;
//        }
//
//        // 4) 重建关系（存在则更新，不存在则插入），收集本次保留的特殊备件ID
//        List<AssetMtplanSpare> rels = new ArrayList<>(items.size());
//        Set<Long> keepIds = new HashSet<>();
//
//        for (SpecialItemDTO it : items) {
//            if (it == null) continue;
//
//            String code = normalizeCode(it.getCode());
//            String name = trim(it.getName());
//            if (isBlank(code) || isBlank(name)) continue;
//
//            // 4.1 找或建 asset_spare
//            Long spareId = spareMapper.selectIdByCode(code);
//            if (spareId == null) {
//                // 新增
//                Spare s = new Spare();
//                s.setCode(code);
//                s.setName(name);
//                s.setType(SPARE_TYPE_SPECIAL);
//                s.setPlanDate(parseDateYMD(it.getPlanDate()));       // java.util.Date / java.sql.Date 均可映射
//                s.setOrderDate(nz(it.getOrderDate()));
//                s.setStockTotal(0L);
//                s.setStockAvailable(0L);
//                s.setUnit("个");
//                s.setStatus(0);
//                s.setRemark("");
//                s.setCreateBy(user);
//                spareMapper.insertSpare(s);
//                spareId = s.getId();
//            } else {
//                // 已有：按“多参数”接口更新必要字段
//                spareMapper.updateSpecialFieldsByCode(
//                        code,
//                        name,
//                        parseDateYMD(it.getPlanDate()),
//                        nz(it.getOrderDate()),
//                        user,
//                        it.getType()
//                );
//            }
//            keepIds.add(spareId);
//
//            // 4.2 建立 plan–spare 关系
//            AssetMtplanSpare r = new AssetMtplanSpare();
//            r.setPlanId(planId);
//            r.setSpareId(spareId);
//            r.setAssetId(it.getAssetId());
//            r.setQty(it.getQty() == null || it.getQty() < 1 ? 1 : it.getQty());
//            r.setRemark("");
//            r.setCreateBy(user);
//            rels.add(r);
//        }
//
//        if (!rels.isEmpty()) {
//            assetMtplanMapper.batchInsert(rels);
//        }
//
//        // 5) 清理“旧有但本次不再使用、且不被其他计划使用”的特殊备件
//        cleanupOrphanSpecials(oldSpecialIds, keepIds);
//    }

    /** 删除孤儿特殊备件（只删 type=1 且不再被任何计划使用的） */
    private void cleanupOrphanSpecials(Set<Long> oldSpecialIds, Set<Long> keepIds) {
        if (oldSpecialIds == null || oldSpecialIds.isEmpty()) return;

        // 本次被移除的旧特殊ID集合
        Set<Long> candidates = oldSpecialIds.stream()
                .filter(id -> !keepIds.contains(id))
                .collect(Collectors.toSet());
        if (candidates.isEmpty()) return;

        // 只保留其中 type=1 的ID
        List<Long> specials = spareMapper.selectSpecialIdsByIds(new ArrayList<>(candidates));
        if (specials == null || specials.isEmpty()) return;

        // 仍在其它计划使用的ID
        List<Long> inUse = assetMtplanMapper.selectInUseSpareIds(specials);
        Set<Long> inUseSet = inUse == null ? Collections.emptySet() : new HashSet<>(inUse);

        // 真正可删的孤儿ID
        List<Long> toDelete = specials.stream()
                .filter(id -> !inUseSet.contains(id))
                .collect(Collectors.toList());
        if (!toDelete.isEmpty()) {
            // 你 Mapper 里已经有 List 版 delete：直接用 List，避免再 Arrays.asList(...)
            spareMapper.deleteSpareByIds(toDelete);
        }
    }

    /* ------------ 小工具 ------------ */

    private static String normalizeCode(String s) {
        return s == null ? null : s.toUpperCase().replaceAll("[^A-Z0-9\\-_]", "");
    }
    private static String trim(String s) { return s == null ? null : s.trim(); }
    private static boolean isBlank(String s) { return s == null || s.trim().isEmpty(); }
    private static int nz(Integer n) { return n == null ? 0 : n; }

    /** 前端通常传 "yyyy-MM-dd"，转换为 java.sql.Date（或 java.util.Date 也可） */
    private static java.util.Date parseDateYMD(String s) {
        if (s == null || s.trim().isEmpty()) return null;
        return java.sql.Date.valueOf(java.time.LocalDate.parse(s.trim()));
    }








}
